﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using JXT.PrimaryKey.Batman.Container;
using JXT.PrimaryKey.Batman.Extensions;
using JXT.PrimaryKey.Batman.Core.Security;
using JXT.PrimaryKey.Batman.Core.Extensions;
using JXT.PrimaryKey.Batman.Core.Infrastructure;
//using JXT.PrimaryKey.Batman.WcfService;
using JXT.PrimaryKey.Batman.WcfService.Client;
using JXT.PrimaryKey.Batman.WcfService.Models;
using JXT.PrimaryKey.Batman.WcfService.Models.UserSystem;
using JXT.PrimaryKey.Batman.WcfService.Interfaces;
using JXT.PrimaryKey.Batman.Web.Security.Converters;

namespace JXT.PrimaryKey.Batman.Web.Security
{
    public class Membership : MembershipBase
    {
        private static readonly string _cookieName = "myshop_infomation_cookie";
        private static readonly string _sessionName = "myshop_infomation_session";

        private IServiceFactory _serviceFactory;

        private SupernovaWebContext _context;

        public Membership(IServiceFactory serviceFactory, SupernovaWebContext context)
        {
            _serviceFactory = serviceFactory;
            _context = context;
        }

        public override bool LoginByName(string name, string password, DateTime? expired = null)
        {
            var result = _serviceFactory.CreateUserService().GetSingle(name);
            return loginByEntity(result, password, expired);
        }

        public override bool LoginByMail(string mail, string password, DateTime? expired = null)
        {
            return false;

            //var result = _serviceFactory.UserService.GetSingleByMail(mail);
            //return loginByEntity(result, password, expired);
        }

        private bool loginByEntity(User user, string password, DateTime? expired = null)
        {
            bool result = user != null && user.Password.Equals(password.ToMd5(), StringComparison.InvariantCultureIgnoreCase);
            if (result)
            {
                Cookie = new SecurityCookie()
                {
                    Guid = Guid.NewGuid(),
                    Id = user.Id,
                    Name = user.Name,
                    Mail = user.Mail
                };
                WriteCookie(Cookie, expired);
                Session = new SessionUser()
                {
                    Id = user.Id,
                    Mail = user.Mail,
                    Name = user.Name,
                    Detail = UserDetailConverter.Instanse.Convert(user.Detail),
                    Status = UserStatusConverter.Instanse.Convert(user.Status)
                };
                fillSessionAuthority(Session, user);
                WriteSession(Session);
            }
            return result;
        }

        protected override SecurityCookie LoadCookie()
        {
            HttpCookie cookie = _context.HttpContext.Request.Cookies[_cookieName];
            try
            {
                if (cookie.Expires != DateTime.MaxValue && cookie.Expires != DateTime.MinValue)
                {
                    Expires = cookie.Expires;
                }
                var cookieObject = AesHelper.Decode(cookie.Value, _context.Configuration.MembershipConfiguration.CookieSecurityKey).ToJsonObject<SecurityCookie>();
                return cookieObject;
            }
            catch
            {
                return SecurityCookie.Default;
            }
        }

        protected override void WriteCookie(SecurityCookie cookie, DateTime? time)
        {
            string cookieString = AesHelper.Encode(cookie.ToJsonString(), _context.Configuration.MembershipConfiguration.CookieSecurityKey);
            HttpCookie httpCookie = new HttpCookie(_cookieName);
            httpCookie.Value = cookieString;
            if (time != null)
            {
                httpCookie.Expires = time.Value;
            }
            _context.HttpContext.Response.Cookies.Add(httpCookie);
        }

        protected override void RemoveCookie()
        {
            WriteCookie(Cookie, DateTime.Now.AddYears(-1));
        }

        protected override void RemoveSession()
        {
            _context.HttpContext.Session.Remove(_sessionName);
        }

        protected override SessionUser LoadSession()
        {
            var session = _context.HttpContext.Session[_sessionName] as SessionUser;
            if (session == null && IsLogin)
            {
                session = CreateSessionUser(Cookie.Id);
            }
            return session;
        }

        protected override void WriteSession(SessionUser session)
        {
            _context.HttpContext.Session[_sessionName] = session;
        }

        protected override SecurityCookie CreateCookie(int userId)
        {
            var user = _serviceFactory.CreateUserService().GetSingle(userId.ToString());
            //var user = _serviceFactory.UserService.GetSingle(userId.ToString());
            if (user != null)
            {
                return new SecurityCookie()
                {
                    Guid = Guid.NewGuid(),
                    Id = user.Id,
                    Mail = user.Mail,
                    Name = user.Name
                };
            }
            return null;
        }

        protected override SessionUser CreateSessionUser(int userId)
        {
            var user = _serviceFactory.CreateUserService().GetSingle(userId.ToString());
            //var user = _serviceFactory.UserService.GetSingle(userId.ToString());
            if (user == null)
                return null;
            var result = new SessionUser()
            {
                Authorities = user.Authorities.ToArray(),
                Id = user.Id,
                Mail = user.Mail,
                Name = user.Name,
                Detail = UserDetailConverter.Instanse.Convert(user.Detail),
                Status = UserStatusConverter.Instanse.Convert(user.Status)
            };
            fillSessionAuthority(result, user);
            return result;
        }

        private static void fillSessionAuthority(SessionUser session, User user)
        {
            List<Authority> authorityList = new List<Authority>();
            if (user != null)
            {
                if (user.Authorities != null)
                {
                    authorityList.AddRange(user.Authorities);
                }
                if (user.Roles != null && user.Roles.Count > 0)
                {
                    foreach (var role in user.Roles)
                    {
                        if (role.Authorities != null)
                        {
                            authorityList.AddRange(role.Authorities);
                        }
                    }
                }
            }
            session.Authorities = authorityList.ToRealAuthorities();
        }
    }
}
